/*the core codes for this gogame app
 *it can operating correctly based on rule
 *of a gogame. some funcionts are made to
 *create connections between scene GUI
 *core calculate all datas represents the
 *whole gogame and scene draw them out
 *to make users enable to interact
 */

 /** 在每次使用核心的接口时需要注意Step, Record与Go本身之间的关系, 问题往往出在需要pass, regret等时候 **/
 /**ifKo() may not so perfect to calculate of a Ko-Status**/

#ifndef GO_H
#define GO_H

#include <utility>
#include <vector>
#include <map>

class Step;
class Record;
class Settings;
class MoveGenerator;

#define DIMENSION 21 //等于棋盘路数再加上2, 2作为边界
#define BLACK 1 //黑子
#define WHITE -1 //白子
#define VOID 0 //空位
#define GRID 9 //越界点
#define ERROR 999 //used in some functions to return a error value
                  //mostly used in some GUI operation when the board
                  //has only one single stone or none stones.

using namespace std; //it is written in an older version
                     //for some std::cout in cmd window
                     //newGame in this file can create a game in
                     //cmd window without GUI

typedef pair<int,int> coordinate; //坐标
typedef vector<coordinate> series; //棋串容器
typedef pair<int,coordinate> io_coordinate; //用于输入输出格式
typedef vector<io_coordinate> io_series; //用于输入输出格式



class Go
{
friend class MoveGenerator;

public:

    Go(); //Constructor
    ~Go(); //Destructor

public: //置于此处的变量是对外需要用到的接口

    /** FIXME **/
    /** 在使用doit()或者pass()时要注意一个问题 **/
    /** pass属性的Step返回坐标(0,0)**/
    /** 要么额外的检查机制, 要么在doit()中加入一个pass()的迭代, 但是GUI的问题??? **/
    void doit(int, int); //数据处理的入口函数, 通过BoardScene::goCore(int,int)连接界面boardscene
    void pass(); //PASS一手棋, 不通过doit()而改变相应的数据以实现这个功能, 涉及众多成员变量的操作
    bool is_allowed_move(int, int); //测试这个位置可不可以着子(禁着点)

    void recoverStep(Step*); //用于获得某一个Step对象的数据, 继而还原与这个Step对象相关的盘面数据
    //bool ifDrawStone(int color, int x, int y); //传递的是需要绘制的棋子颜色参数只有可能使1或-1, 判断是否需要重新绘制某一座标上的棋子
    void initZeroStep(); //用作第零步棋的数据初始化, 即空的盘面时候的数据
    void coverLatestStep(Step*); //覆盖latestStep
    bool ifCoverLatest(); //判断是否要覆盖掉latestStep, 内部实现有一个关联的成员变量作为开关, 用于coverLatestStep(Step*)中
    void setIcl(bool);
    coordinate regret();

    unsigned int block_index; //棋块累加计数器, 用于整盘棋局中, 从1开始. 同时当前值为当前已下的手数+1
    int whos_turn; //决定轮到哪方着子, 只应存在两种状态, 1(BLACK)或者-1(WHITE)
    series drawSerie; //由函数getSerie进行操作, 获得一个提供给图形界面的series
    bool game_status; //true为正常状态, false表示复盘状态
    int board[DIMENSION][DIMENSION]; //创建一个由数组组成数字棋盘 , 其元素的值代表相应位置的状况, -1为白, 1为黑, 0为空 ,9表示越界点

    Step *latestStep; //用于backToInit按钮的相关调用
    Step *tempLatestStep; //存放status为true时的最新的对象, 命名应该与上面的互换更好
    Record *record; //棋局记录器

    //游戏设置相关参数
    int handicapsValue;
    void changeHandicaps(int);

    //读取sgf格式文件后的相关内部数据处理函数
    bool load_changeHandicaps(Settings*);

    //MoveGenerator&searhAlgo Interfaces
    bool ifMoveGenCreated();
    void createMoveGenerator();
    coordinate moveGen_ABMinMax();
    bool if_ban_moves(int, int);

protected:
    const series * get_ban_moves();       //只在moveGenerator::createMirrorCore()中被调用
    void write_ban_moves(const series *); //只在moveGenerator::createMirrorCore()中被调用

private:

    /* core functions with them app can operating a gogame correctly */
    void init();
    int getLiberty(int, int); //Liberty as Lives of stone(s)
    int init_getLiberty(int, int);
    void getBlock(int, int); //Block as Dragon in gogame
    void init_getBlock(int, int);
    void take(int, int); //if need to take off some stones
    bool ifKo(int, int); //some things with ko judgement
    void getSerie(int, int); //获得每轮状态的需绘制的图形对象vector, 放入drawSerie中
                             //with this to tell scene what to draw&delete every turn
    coordinate internal_moveGen_ABMinMax(); //invoked by moveGen_ABMinMax
    bool is_spec_allowed_move(int, int); //额外着子的限制的判定(禁着点以外的额外限定)
    void newGame(); //cmd下无图形界面测试的入口函数

private:

    bool icl; //开关用于ifCoverLatest函数的内部实现, 控制latestStep对象的覆盖
    bool on_off; //控制算气函数中的静态局部变量的归零工作
    series ser0; //零时存放当前棋串的容器
    map<int,series> all_block; //定义这种数据类型用于储存所有的棋块信息, first为棋块编号, second为vector<pair<int,int>>类型, 表示该棋块的所有棋子坐标
    int life; //算气函数中要用到的全局变量, 不受递归的影响

    unsigned int block[DIMENSION][DIMENSION]; //统计每个坐标上棋子属于哪个棋块, 0表示无, 1或1以上为棋块序列
    int ko[DIMENSION][DIMENSION]; //ifko函数中的数据表示
    int count[DIMENSION][DIMENSION]; //防止重复递归的变量

    Step *tempStep; //pointer pointing to new Step object everytime
    Step *zeroStep; //it represent the init status of the board, with handicaps it will be different
                    //in this Step obj, only board[][DIMENSION] can be used

    MoveGenerator *moveGen;
    series _ban_moves; //reset by (internal)moveGen_ABMinMax()
};

#endif // GO_H
